package com.abel.bigwater.data.sanchuan

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.data.Bit32Array
import io.netty.buffer.ByteBuf
import org.joda.time.LocalTime
import kotlin.experimental.and

class WarnDataPart(_dataLen: Int?) : SanchuanData(_dataLen) {
    /**
     * 1 需报警条数 J 表示本次需要将上传多少条告警纪录，上报昨天未上报的告警。
     */
    var jcount: Short? = null

    /**
     * 1 当前报警条数 K 表示本次实际上传多少条告警纪录
     */
    var kcount: Short? = null

    /**
     * 4*K
    报警纪录 1 报警纪录 4 字节，格式如下：
    第 1~3 字节
    当前警告所对应的时间。时分秒（采用 BCD 码）。详见参数表，参数编码 0006。
    第 4 字节 BIT0~4
    当告警类型为故障告警时： 0~31 对应各种故障告警(参考读故障/复位纪录 BIT0-4 定义)
    第 4 字节 BIT5
    0 警告消失
    1 警告产生
    第 4 字节 BIT6
    辅助标志
    第 4 字节 BIT7
    暂未定义
    …
    报警纪录 K
     */
    var warnList: ArrayList<WarnRow>? = null


    /**
     * 计算数据长度，针对解析和打包
     */
    override fun computeDataLen(): Int {
        dataLen = 1 + 1 + 4 * kcount!!

        return dataLen!!
    }

    /**
     * 从当前位置写入打包字节流
     */
    override fun fillBuffer(buf: ByteBuf) {
        assert(kcount?.toInt() == (warnList?.size ?: 0))

        buf.writeBytes(buf.alloc().buffer().apply {
            writeByte(jcount!!.toInt())
            writeByte(kcount!!.toInt())

            for (wr in warnList.orEmpty()) {
                assert(wr.warnTimeStr?.size == 3)
                writeBytes(wr.warnTimeStr!!.hexArray)

                writeByte(wr.warnFlag!!.back)
            }
        })
    }

    /**
     * 解析字节流，从buf当前位置开始，并且消费其中的字节。
     */
    override fun <T : SanchuanData> parseBuffer(buf: ByteBuf): T? {
        buf.duplicate().apply {
            jcount = readByte().toShort().and(0xFF)
            kcount = readByte().toShort().and(0xFF)
        }

        computeDataLen()

        buf.readBytes(dataLen!!).apply {
            skipBytes(2)

            warnList = ArrayList()
            for (idx in 0..(kcount!! - 1)) {
                warnList!!.add(WarnRow().also {
                    it.warnTimeStr = BcdString.create(this@apply, 3)
                    it.warnFlag = WarnType(this.readByte().toInt().and(0xFF))
                })
            }
        }

        return this as T
    }

}

/**
 *
报警纪录 1 报警纪录 4 字节，格式如下：
第 1~3 字节
当前警告所对应的时间。时分秒（采用 BCD 码）。详见参数表，参数编码 0006。
第 4 字节 BIT0~4
当告警类型为故障告警时： 0~31 对应各种故障告警(参考读故障/复位纪录 BIT0-4 定义)
第 4 字节 BIT5
0 警告消失
1 警告产生
第 4 字节 BIT6
辅助标志
第 4 字节 BIT7
暂未定义
 */
class WarnRow {
    var warnTimeStr: BcdString? = null

    var warnTime: LocalTime? = null
        get() {
            field = if (warnTimeStr == null) null
            else LocalTime(warnTimeStr!!.bcdArray!![0].toInt(),
                    warnTimeStr!!.bcdArray!![1].toInt(),
                    warnTimeStr!!.bcdArray!![2].toInt())

            return field
        }
        set(value) {
            if (value == null) warnTimeStr = null
            else {
                warnTimeStr = BcdString(byteArrayOf(value.hourOfDay.toByte(),
                        value.minuteOfHour.toByte(), value.secondOfMinute.toByte()), true)
            }
        }

    var warnFlag: WarnType? = null

}

/**
 *
第 4 字节 BIT0~4
当告警类型为故障告警时： 0~31 对应各种故障告警(参考读故障/复位纪录 BIT0-4 定义)
第 4 字节 BIT5
0 警告消失
1 警告产生
第 4 字节 BIT6
辅助标志
第 4 字节 BIT7
暂未定义
 */
class WarnType(v1: Int) : Bit32Array(v1) {
    var errorTypeId: Int
        get() = get(0, 4)
        set(value) {
            set(0, 4, value)
        }

    var warnCome: Boolean
        get() = get(5) == 1
        set(value) {
            set(5, if (value) 1 else 0)
        }

    var subFlag: Int
        get() = get(6)
        set(value) {
            set(6, value)
        }

    override fun toString(): String {
        return "0${back.toString(16)}".takeLast(2)
    }
}
